﻿// -------------------------------------------------------------------------
//    @FileName         :    NFItemDefine.cpp
//    @Author           :    gaoyi
//    @Date             :    24-11-19
//    @Email            :    445267987@qq.com
//    @Module           :    NFItemDefine
//
// -------------------------------------------------------------------------

#include "NFItemDefine.h"
#include "BagPage/NFBagPageOpDefine.h"
#include "proto_common_bag.nanopb.h"
#include "proto_cs.pb.h"

int NFItemUtil::ItemToCSData(const NFGridItem& item, proto_ff::ItemGridCSData& pbData, int index)
{
    pbData.set_index(index);
    int iRet = item.ToPb(&pbData);
    CHECK_RET(iRet, "ItemToCSData Failed:{}", item.ShortDebugString());
    return iRet;
}

int NFItemUtil::ItemToCSData(const NFGridItem& item, ItemGridCSData& stData)
{
    proto_ff::ItemGridCSData stPbData;
    int iRet = ItemToCSData(item, stPbData, 0);
    if (iRet == 0)
    {
        stData.FromPb(stPbData);
    }
    return 0;
}

int NFItemUtil::ItemToCSData(const Item* pItem, proto_ff::ItemGridCSData* pItemCSData)
{
    CHECK_NULL(0, pItem);
    CHECK_NULL(0, pItemCSData);
    pItemCSData->mutable_base()->set_id(pItem->id);
    pItemCSData->mutable_base()->set_quality(pItem->quality);
    pItemCSData->mutable_base()->set_value(pItem->value);
    return 0;
}

int NFItemUtil::ItemFromCSData(NFGridItem& item, const proto_ff::ItemGridCSData* pData)
{
    int iRet = item.FromPb(*pData);
    CHECK_RET(iRet, "ItemFromCSData Faield:{}", pData->ShortDebugString());
    return 0;
}

int NFItemUtil::ItemFromCSData(NFGridItem& item, const proto_ff::ItemGridCSData& stData)
{
    return ItemFromCSData(item, &stData);
}

void NFItemUtil::SetToGrid(GridItemBase& base, uint32_t id, int quality, uint64_t value, uint64_t uuid, uint32_t trade_cooldown, uint32_t effective_time, bool bind)
{
    base.Init();
    base.id = id;
    base.quality = quality;
    base.value = value;
    base.uuid = uuid;
    base.trade_cooldown = trade_cooldown;
    base.effective_time = effective_time;
    base.role_bind = bind;
}

bool NFItemUtil::IsSameItem(const GridItemBase& a, const GridItemBase& b)
{
    if (a.id == b.id && a.quality == b.quality && a.uuid == b.uuid && a.trade_cooldown == b.trade_cooldown && a.effective_time == b.effective_time && a.role_bind == b.role_bind)
    {
        return true;
    }

    return false;
}

bool NFItemUtil::IsSameItem(const GridItemBase& a, uint32_t id, int quality, uint64_t uuid, uint32_t trade_cooldown, uint32_t effective_time, bool role_bind)
{
    if (a.id == id && a.quality == quality && a.uuid == uuid && a.trade_cooldown == trade_cooldown && a.effective_time == effective_time && a.role_bind == role_bind)
    {
        return true;
    }

    return false;
}

bool NFItemUtil::IsEmptyGrid(const NFGridItem* pData)
{
    if (pData == NULL)
        return true;
    if (pData->m_stBase.id == 0 || pData->m_stBase.value == 0)
        return true;

    return false;
}

bool NFItemUtil::IsEmptyGrid(const NFGridItem& stItem)
{
    return stItem.IsEmpty();
}

NFItemSorter::NFItemSorter(int iMaxItemNum)
{
    m_iMaxItemNum = iMaxItemNum;
    if (m_iMaxItemNum > (int)m_itemsInfo.max_size())
    {
        LOGSVR_FATAL("list size error: " << iMaxItemNum);
        m_iMaxItemNum = m_itemsInfo.max_size();
        return;
    }
}

NFItemSorter::~NFItemSorter()
{
}

int NFItemSorter::Append(NFGridItem& stItem)
{
    if (stItem.m_stBase.id == 0 && stItem.m_stBase.value == 0 && stItem.m_stBase.uuid == 0)
    {
        return 0;
    }

    if ((int)m_itemsInfo.size() >= m_iMaxItemNum)
    {
        LOGSVR_ERROR("FULL : " << m_itemsInfo.size() << " " << m_iMaxItemNum);
        return -1;
    }

    if (stItem.m_stBase.uuid > 0)
    {
        m_itemsInfo.push_back(stItem);
        return 0;
    }

    for (int i = 0; i < (int)m_itemsInfo.size(); i++)
    {
        if (NFItemUtil::IsSameItem(m_itemsInfo[i].m_stBase, stItem.m_stBase))
        {
            m_itemsInfo[i].m_stBase.value += stItem.m_stBase.value;
            return 0;
        }
    }

    m_itemsInfo.push_back(stItem);
    return 0;
}

int NFItemSorter::Get(int index, NFGridItem& item)
{
    CHECK_EXPR(index >= 0 && index < (int)m_itemsInfo.size(), -1, " Index error:{} max:{} ", index, m_itemsInfo.size());
    item = m_itemsInfo[index];
    return 0;
}

void NFItemSorter::Sort()
{
    m_itemsInfo.sort(CompareGridItem);
}

bool NFItemSorter::CompareGridItem(const NFGridItem& a, const NFGridItem& b)
{
    if (a.m_iItemType < b.m_iItemType)
    {
        return true;
    }
    else if (a.m_iItemType == b.m_iItemType)
    {
        if (a.m_stBase.id < b.m_stBase.id)
        {
            return true;
        }
        else if (a.m_stBase.id == b.m_stBase.id)
        {
            if (a.m_stBase.quality < b.m_stBase.quality)
            {
                return true;
            }
            else if (a.m_stBase.quality == b.m_stBase.quality)
            {
                if ((int)a.m_stBase.role_bind < (int)b.m_stBase.role_bind)
                {
                    return true;
                }
                else if ((int)a.m_stBase.role_bind == (int)b.m_stBase.role_bind)
                {
                    return a.m_stBase.value < b.m_stBase.value;
                }
            }
        }
    }

    return false;
}

bool NFItemUtil::IsNormalItem(proto_ff::enItemType eType)
{
    switch (eType)
    {
        case proto_ff::EN_ITEM_TYPE_BUFF:
        case proto_ff::EN_ITEM_TYPE_PROP:
        case proto_ff::EN_ITEM_TYPE_MATERIAL:
        case proto_ff::EN_ITEM_TYPE_TITLE:
        case proto_ff::EN_ITEM_TYPE_BOX:
        case proto_ff::EN_ITEM_TYPE_GEMSTONE:
        case proto_ff::EN_ITEM_TYPE_MISC:
        case proto_ff::EN_ITEM_TYPE_RANDOM_QUALITY:
        case proto_ff::EN_ITEM_TYPE_PARTNER_EQUIP_STONE:
            return true;
        default:
            return false;
    }

    return false;
}

bool NFItemUtil::IsUUIDItem(proto_ff::enItemType eType)
{
    switch (eType)
    {
        case proto_ff::EN_ITEM_TYPE_EQUIP:
        case proto_ff::EN_ITEM_TYPE_TREASUREMAP:
        case proto_ff::EN_ITEM_TYPE_SKIN:
        case proto_ff::EN_ITEM_TYPE_PARTNER_EQUIP:
        case proto_ff::EN_ITEM_TYPE_BUFF_EQUIP:
            return true;
        default:
            break;
    }
    return false;
}

bool NFItemUtil::IsHeroPieceKeyMaterial(proto_ff::enItemType eType, int iSubType)
{
    if (eType == proto_ff::EN_ITEM_TYPE_MATERIAL && iSubType == proto_ff::EN_MAT_HERO_PIECE_KEY)
    {
        return true;
    }

    return false;
}

bool NFItemUtil::IsInBag(NFItemIndex* index_info)
{
    if (index_info)
    {
        switch (index_info->page)
        {
            case proto_ff::EN_BPT_EQUIP:
            case proto_ff::EN_BPT_MATRIAL:
            case proto_ff::EN_BPT_PROP:
            case proto_ff::EN_BPT_TITLE:
            case proto_ff::EN_BPT_SKIN:
            case proto_ff::EN_BPT_PARTNER_EQUIP:
            case proto_ff::EN_BPT_PARTNER_EQUIP_STONE:
            case proto_ff::EN_BPT_BUFF_EQUIP:
                return true;
            default:
                break;
        }
    }
    return false;
}

bool NFItemUtil::IsDressed(NFItemIndex* index_info)
{
    if (index_info)
    {
        if (index_info->page == proto_ff::EN_BPT_DRESSED_ITEM)
            return true;
    }
    return false;
}

int NFItemUtil::ItemToEquip(NFGridItem& item, Equip& equip)
{
    CHECK_EXPR(item.m_iItemType == proto_ff::EN_ITEM_TYPE_EQUIP, -1, "type not match: {}", item.m_iItemType);
    equip.base = item.m_stBase;
    auto pExt = item.m_uniExt.get_m_stData_m_stEquip();
    CHECK_NULL(0, pExt);
    equip.ext = *pExt;
    return 0;
}

int NFItemUtil::ItemToMap(NFGridItem& item, TreasureMap& map)
{
    CHECK_EXPR(item.m_iItemType == proto_ff::EN_ITEM_TYPE_TREASUREMAP, -1, "type not match: {}", item.m_iItemType);
    map.base = item.m_stBase;
    auto pExt = item.m_uniExt.get_m_stData_m_stTreasureMap();
    CHECK_NULL(0, pExt);
    map.ext = *pExt;
    return 0;
}

int NFItemUtil::ItemToPartnerEquip(NFGridItem& item, PartnerEquip& equip)
{
    CHECK_EXPR(item.m_iItemType == proto_ff::EN_ITEM_TYPE_PARTNER_EQUIP, -1, "type not match: {}", item.m_iItemType);
    equip.base = item.m_stBase;
    auto pExt = item.m_uniExt.get_m_stData_m_stPartnerEquip();
    CHECK_NULL(0, pExt);
    equip.ext = *pExt;
    return 0;
}

int NFItemUtil::GetItemPileNumMax(int iItemId, int& iPileNumMax)
{
    auto pDesc = ItemDesc::Instance()->GetDesc(iItemId);
    if (pDesc)
    {
        iPileNumMax = pDesc->item_max_overlap;
        if (iPileNumMax == 0)
        {
            switch (pDesc->item_type)
            {
                case proto_ff::EN_ITEM_TYPE_EQUIP:
                case proto_ff::EN_ITEM_TYPE_TREASUREMAP:
                case proto_ff::EN_ITEM_TYPE_SKIN:
                case proto_ff::EN_ITEM_TYPE_PARTNER_EQUIP:
                case proto_ff::EN_ITEM_TYPE_BUFF_EQUIP:
                {
                    iPileNumMax = 1;
                    break;
                }
                default:
                {
                    iPileNumMax = std::numeric_limits<int>::max();
                    break;
                }
            }
        }
    }
    return 0;
}

int NFItemUtil::GetItemPileNumMax(int iItemId)
{
    int iPileNumMax = 0;
    GetItemPileNumMax(iItemId, iPileNumMax);
    return iPileNumMax;
}

int NFItemUtil::CalcAddBagType(const WillAddItemData& stWillAddWareData, int enPackageOpReason, int& iBagType)
{
    auto pDesc = ItemDesc::Instance()->GetDesc(stWillAddWareData.id);
    CHECK_NULL(0, pDesc);
    CHECK_EXPR(IsValidBagType(pDesc->bag_page_type), -1, "pDesc->bag_page_type:{}", pDesc->bag_page_type);

    iBagType = pDesc->bag_page_type;
    return 0;
}

int NFItemUtil::CalcAddBagType(const NFGridItem& stItem, int enPackageOpReason, int& iBagType)
{
    auto pDesc = ItemDesc::Instance()->GetDesc(stItem.GetItemID());
    CHECK_NULL(0, pDesc);
    CHECK_EXPR(IsValidBagType(pDesc->bag_page_type), -1, "pDesc->bag_page_type:{}", pDesc->bag_page_type);

    iBagType = pDesc->bag_page_type;
    return 0;
}

int NFItemUtil::CalcAddBagType(int iItemID, int enPackageOpReason, int& iBagType)
{
    auto pDesc = ItemDesc::Instance()->GetDesc(iItemID);
    CHECK_NULL(0, pDesc);
    CHECK_EXPR(IsValidBagType(pDesc->bag_page_type), -1, "pDesc->bag_page_type:{}", pDesc->bag_page_type);

    iBagType = pDesc->bag_page_type;
    return 0;
}

bool NFItemUtil::IsValidBagType(int iBagType)
{
    if (iBagType == EN_BPT_TEMP_STORAGE || iBagType == EN_BPT_DRESSED_ITEM || (iBagType >= EN_BPT_EQUIP && iBagType <= _enBagPageType_MAX))
    {
        return true;
    }
    return false;
}

bool NFItemUtil::IsValidOpBagType(int iBagType)
{
    if (iBagType >= EN_BPT_EQUIP && iBagType <= _enBagPageType_MAX)
    {
        return true;
    }
    return false;
}

int NFItemUtil::GetSuitableBag(int iItemID, int enPackageOpReason, int& iBagType)
{
    auto pDesc = ItemDesc::Instance()->GetDesc(iItemID);
    CHECK_NULL(0, pDesc);
    CHECK_EXPR(IsValidBagType(pDesc->bag_page_type), -1, "pDesc->bag_page_type:{}", pDesc->bag_page_type);

    iBagType = pDesc->bag_page_type;
    return 0;
}

int NFItemUtil::GetBagTabsForDel(const WillDelItemData& stWillDelItemData, std::vector<int>& aiBagType)
{
    int iRetCode = 0;

    int iBagType = INVALID_ID;
    iRetCode = GetSuitableBag(stWillDelItemData.m_iItemID, 0, iBagType);
    CHECK_ERR(0, iRetCode, "GetSuitableBag failed, itemId:{}", stWillDelItemData.m_iItemID);
    aiBagType.push_back(iBagType);
    return 0;
}

bool NFItemUtil::IsValidMoney(int iMoneyType)
{
    auto pDesc = ItemDesc::Instance()->GetDesc(iMoneyType);
    if (pDesc && pDesc->item_type == proto_ff::EN_ITEM_TYPE_COIN)
    {
        return true;
    }
    return false;
}

FF_IG_LIST* NFItemUtil::MutableList(proto_ff::Proto_CSRoleItemNtf* ntf, int iPageType)
{
    if (!ntf)
        return NULL;

    switch (iPageType)
    {
        case proto_ff::EN_BPT_TEMP_STORAGE:
            return ntf->mutable_temp_storage_list();
        case proto_ff::EN_BPT_DRESSED_ITEM:
            return ntf->mutable_dressed_list();
        case proto_ff::EN_BPT_EQUIP:
            return ntf->mutable_grids_for_equip();
        case proto_ff::EN_BPT_STORAGE:
            return ntf->mutable_storage_list();
        case proto_ff::EN_BPT_MATRIAL:
            return ntf->mutable_grids_for_matrial();
        case proto_ff::EN_BPT_PROP:
            return ntf->mutable_grids_for_prop();
        case proto_ff::EN_BPT_SKIN:
            return ntf->mutable_grids_for_skin();
        case proto_ff::EN_BPT_TITLE:
            return ntf->mutable_grids_for_title();
        case proto_ff::EN_BPT_GEM:
            return ntf->mutable_grids_for_gem();
        case proto_ff::EN_BPT_PARTNER_EQUIP:
            return ntf->mutable_grids_for_partner_equip();
        case proto_ff::EN_BPT_PARTNER_EQUIP_STONE:
            return ntf->mutable_grids_for_partner_equip_stone();
        case proto_ff::EN_BPT_PARTNER_TOKEN:
            return ntf->mutable_grids_for_partner_token();
        case proto_ff::EN_BPT_BUFF_EQUIP:
            return ntf->mutable_grids_for_buff_equip();
        default:
            break;
    }

    return NULL;
}

void NFItemUtil::AddToNtf(const Item* pItemData, FF_ITEM_LIST* ntf)
{
    if (pItemData && ntf)
        pItemData->ToPb(ntf->Add());
}

void NFItemUtil::AddToNtf(const Item* pItemData, FF_IG_LIST* ntf)
{
    if (pItemData && ntf)
    {
        proto_ff::ItemGridCSData* p = ntf->Add();
        p->mutable_base()->set_id(pItemData->id);
        p->mutable_base()->set_quality(pItemData->quality);
        p->mutable_base()->set_value(pItemData->value);
    }
}

void NFItemUtil::AddToNtf(uint32_t iID, int iQuality, uint64_t iValue, FF_ITEM_LIST* ntf)
{
    if (ntf)
    {
        proto_ff::Item* p = ntf->Add();
        p->set_id(iID);
        p->set_quality(iQuality);
        p->set_value(iValue);
    }
}

void NFItemUtil::AddToNtf(uint32_t iID, int iQuality, uint64_t iValue, FF_IG_LIST* ntf)
{
    if (ntf)
    {
        proto_ff::ItemGridCSData* p = ntf->Add();
        p->mutable_base()->set_id(iID);
        p->mutable_base()->set_quality(iQuality);
        p->mutable_base()->set_value(iValue);
    }
}

void NFItemUtil::AddToNtf(const NFGridItem* pData, FF_IG_LIST* ntf, int index)
{
    if (pData && ntf)
        NFItemUtil::ItemToCSData(*pData, *(ntf->Add()), index);
}

void NFItemUtil::AddToNtfChangeNum(const NFGridItem* pData, FF_IG_LIST* ntf, int iNum)
{
    if (pData && ntf)
    {
        auto pAdd = ntf->Add();
        ItemToCSData(*pData, *pAdd, 0);
        pAdd->mutable_base()->set_value(iNum);
    }
}

bool NFItemUtil::ItemCanAddToBagPage(const E_Item* pItemDesc, int iPageType)
{
    CHECK_EXPR(pItemDesc, false, "iPageType:{}", iPageType);
    switch (pItemDesc->item_type)
    {
        case proto_ff::EN_ITEM_TYPE_BUFF:
        case proto_ff::EN_ITEM_TYPE_PROP:
        case proto_ff::EN_ITEM_TYPE_TITLE:
        case proto_ff::EN_ITEM_TYPE_MATERIAL:
        case proto_ff::EN_ITEM_TYPE_BOX:
        case proto_ff::EN_ITEM_TYPE_GEMSTONE:
        case proto_ff::EN_ITEM_TYPE_PARTNER_EQUIP_STONE:
        case proto_ff::EN_ITEM_TYPE_RANDOM_QUALITY:
        case proto_ff::EN_ITEM_TYPE_EQUIP:
        case proto_ff::EN_ITEM_TYPE_TREASUREMAP:
        case proto_ff::EN_ITEM_TYPE_SKIN:
        case proto_ff::EN_ITEM_TYPE_PARTNER_EQUIP:
        case proto_ff::EN_ITEM_TYPE_BUFF_EQUIP:
        {
            if (iPageType == proto_ff::EN_BPT_TEMP_STORAGE || iPageType == proto_ff::EN_BPT_STORAGE)
            {
                return true;
            }
            else if (iPageType == proto_ff::EN_BPT_DRESSED_ITEM)
            {
                return pItemDesc->item_type == EN_ITEM_TYPE_EQUIP;
            }
            else
            {
                return pItemDesc->bag_page_type == iPageType;
            }
        }
        case proto_ff::EN_ITEM_TYPE_COIN:
        case proto_ff::EN_ITEM_TYPE_ID:
            return false;
        default:
            return false;
    }
    return false;
}


bool NFItemUtil::IsSameItem(const WillAddItemData& a, const NFGridItem& b)
{
    if (a.id == b.m_stBase.id && a.quality == b.m_stBase.quality && 0 == b.m_stBase.uuid && a.trade_cooldown == b.m_stBase.trade_cooldown && a.effective_time == b.m_stBase.effective_time && a.role_bind == b.m_stBase.role_bind)
    {
        return true;
    }

    return false;
}

bool NFItemUtil::IsSameItem(const SelectItemGridParam& a, const NFGridItem& b)
{
    if ((int)a.base.id == b.GetItemID() && (int)a.base.quality == b.GetQuality() && a.base.uuid == b.GetUUID() && a.base.trade_cooldown == b.GetTradeCoolDown() && a.base.effective_time == b.GetEffectTime() && a.base.role_bind == b.IsBind())
    {
        return true;
    }

    return false;
}

bool NFItemUtil::IsSameItemNotConsiderBind(const SelectItemGridParam& a, const NFGridItem& b)
{
    if ((int)a.base.id == b.GetItemID() && (int)a.base.quality == b.GetQuality() && a.base.uuid == b.GetUUID() && a.base.trade_cooldown == b.GetTradeCoolDown() && a.base.effective_time == b.GetEffectTime())
    {
        return true;
    }

    return false;
}

int NFItemUtil::GetCanPileNumMax(const WillAddItemData& fromItem, const NFGridItem& toItem, int& iCanPileNumMax)
{
    iCanPileNumMax = 0;

    if (toItem.IsEmpty())
    {
        return 0;
    }

    if (!IsSameItem(fromItem, toItem))
    {
        return 0;
    }

    int iPileNumMax = NFItemUtil::GetItemPileNumMax(fromItem.id);
    iCanPileNumMax = iPileNumMax - toItem.GetNumber();

    return 0;
}

bool NFItemUtil::IsBind(bool bBind, const E_Item& desc, int eBindType)
{
    bool bind_role = false;
    switch (eBindType)
    {
        case EN_BT_AUTO:
        {
            bind_role = bBind ? bBind : desc.forbit_save_and_sell;
            break;
        }
        case EN_BT_FORCE_BIND:
        {
            bind_role = true;
            break;
        }
        case EN_BT_FORCE_NOT_BIND:
        case EN_BT_REMOVE_BIND:
        {
            bind_role = false;
            break;
        }
        default:
        {
            return false;
        }
    }
    return bind_role;
}

bool NFItemUtil::ItemOpDataCompareFunForDel(const ItemOpData& left, const ItemOpData& right)
{
    auto pItemLeft = left.pItem;
    auto pItemRight = right.pItem;

    if (pItemLeft->IsBind() != pItemRight->IsBind())
    {
        return pItemLeft->IsBind();
    }

    // 快过期的优先
    if (pItemLeft->GetEffectTime() != pItemRight->GetEffectTime())
    {
        return pItemLeft->GetEffectTime() < pItemRight->GetEffectTime();
    }

    // 交易所下次可交易时间久的优先
    if (pItemLeft->GetTradeCoolDown() != pItemRight->GetTradeCoolDown())
    {
        return pItemLeft->GetTradeCoolDown() > pItemRight->GetTradeCoolDown();
    }

    // 叠加数小的优先
    if (pItemLeft->GetNumber() != pItemRight->GetNumber())
    {
        return pItemLeft->GetNumber() < pItemRight->GetNumber();
    }

    return pItemLeft->GetUUID() < pItemRight->GetUUID();
}


uint64_t NFItemUtil::GetCanGainMoneyNum(int iMoneyType)
{
    auto pDesc = ItemDesc::Instance()->GetDesc(iMoneyType);
    if (pDesc)
    {
        return pDesc->item_max_hold;
    }
    return 0;
}

bool NFItemUtil::IsVirtualMoney(int moneyType)
{
    if (moneyType == EN_ID_EXP || moneyType == EN_ID_PET_EXP || moneyType == EN_ID_GUILD_BOUNS || moneyType == EN_ID_GUILD_COIN || moneyType == EN_ID_EP || moneyType == EN_ID_ACTIVATE_FP || moneyType == EN_ID_FROZE_FP || moneyType == EN_ID_CONTRIBUTION || moneyType == EN_ID_EXPLORER_MEDAL ||
        moneyType == EN_ID_EXPLORER_SALARY || moneyType == EN_ID_INFINITE_DUNGEON_SHARE_SCORE)
    {
        return true;
    }
    return false;
}
